home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ShareWare OnLine 2
/
ShareWare OnLine Volume 2 (CMS Software)(1993).iso
/
os2
/
mklapi10.zip
/
MKLAPI.DOC
< prev
next >
Wrap
Text File
|
1993-05-04
|
116KB
|
2,878 lines
MKLAPI
Märklin-Interface driver and
High Level Language
Application Programming Interface
for C-language and BASIC
Version 1.0
Document Number RH-MKLAPI 1.0
May 4, 1993
Rob Hamerling
Vianen-ZH
The Netherlands
Phone: 31-3473-72136 (voice)
FIDO: 2:512/4.1098
MKLAPI
MKLAPI
───────────────────────────────────────────────────────────────────────────
CONTENTS
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
What is MKLAPI? . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Realisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Registration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Functional description . . . . . . . . . . . . . . . . . . . . . . . . 3
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Functional Requirements . . . . . . . . . . . . . . . . . . . . . . . 3
Provided Facilities . . . . . . . . . . . . . . . . . . . . . . . . . 4
Deliverables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Restrictions and Limitations . . . . . . . . . . . . . . . . . . . . . 5
Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
C-language framework . . . . . . . . . . . . . . . . . . . . . . . . . 7
QuickBASIC framework . . . . . . . . . . . . . . . . . . . . . . . . . 8
Sample programs . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
OS/2 and DOS differences . . . . . . . . . . . . . . . . . . . . . . 10
Specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Available Functions . . . . . . . . . . . . . . . . . . . . . . . . . 11
mklclose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
mklflush . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
mklgetsn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
mklgo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
mklmsecs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
mklopen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
mklpoll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
mklpurge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
mklputc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
mklsleep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
mklsound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
mklstats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
mklstop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
mkltime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
mkltrace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Macro Specifications . . . . . . . . . . . . . . . . . . . . . . . . 23
mklput1c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
mklput2c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Use of timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
QuickBASIC Function Specifications . . . . . . . . . . . . . . . . . 25
Errors and Signals . . . . . . . . . . . . . . . . . . . . . . . . . 25
Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Application development considerations . . . . . . . . . . . . . . . 27
C-Compiler considerations . . . . . . . . . . . . . . . . . . . . . . 27
MicroSoft QuickBASIC compiler 4.5 Considerations . . . . . . . . . . 27
Building an EXE-file . . . . . . . . . . . . . . . . . . . . . . . . 27
C-language and DOS . . . . . . . . . . . . . . . . . . . . . . . . 28
C-language and BASIC . . . . . . . . . . . . . . . . . . . . . . . 28
C-language and OS2 1.3 . . . . . . . . . . . . . . . . . . . . . . 29
───────────────────────────────────────────────────────────────────────────
Contents ii
MKLAPI
───────────────────────────────────────────────────────────────────────────
C-language and OS2 2.0+ . . . . . . . . . . . . . . . . . . . . . . 30
Storage and performance . . . . . . . . . . . . . . . . . . . . . . . 30
Memory Utilisation . . . . . . . . . . . . . . . . . . . . . . . . 30
Processor utilisation . . . . . . . . . . . . . . . . . . . . . . . 30
Comments, Remarks, Bug-reports . . . . . . . . . . . . . . . . . . . 31
Appendix A. MKLAPI Internals . . . . . . . . . . . . . . . . . . . . 32
Multitasking . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Reading Märklin S88 encoders . . . . . . . . . . . . . . . . . . . . 33
Communications Interface Specification . . . . . . . . . . . . . . . 35
Problems with OS/2 COM[xx].SYS . . . . . . . . . . . . . . . . . . . 37
OS/2 and DOS differences . . . . . . . . . . . . . . . . . . . . . . 38
Appendix B. Trace facility . . . . . . . . . . . . . . . . . . . . . 40
Trace records . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
| Appendix C. Märklin-Interface peculiarities . . . . . . . . . . . . 41
Appendix D. Summary of changes . . . . . . . . . . . . . . . . . . . 42
────────────────────
(1) This document is processed: on May 4, 1993 at 9:52 p.m.
───────────────────────────────────────────────────────────────────────────
Contents iii
MKLAPI
───────────────────────────────────────────────────────────────────────────
INTRODUCTION
Copyright (C) R. Hamerling, 1991, 1993
All Rights Reserved.
WHAT IS MKLAPI?
MKLAPI is a combination of:
■ a driver for buffered communications, automatic reading of Märklin S88
encoder-boxes, timer- and some other services.
■ a number of user callable routines for common elementary functions, with
a comfortable high-level programming interface.
So MKLAPI reliefs a programmer from 'low-level' tasks such as controlling
the communication with the Märklin-Interface, so that he can concentrate on
the railroad-control logic. This simplifies programming for
model-railroads which are controlled via a Märklin-Interface. Internally
it performs a kind of multi-tasking, which is highly desirable for this
realtime environment ('proces control').
PURPOSE
The driver and API has been developed for the following purposes:
■ have an application programming interface (API) which is independent of
the operating system (i.c. OS/2 or DOS).
■ provide a simple interface for a number of frequently used basic control
functions such as sending commands to trains and switch points, and
reading sensors.
■ allow the mainline to be written completely in high-level programming
language (i.c. C-language or QuickBASIC).
■ obtain a buffered communications facility to the Märklin-Interface,
including automatic flow control as required by the Märklin-Interface.
■ have 'background' tasks for a number of functions that should or could
be performed independently and asynchronously from the mainline.
■ provide an accurate and efficient timer facility for time-dependent
operations, events and interval-calculations.
───────────────────────────────────────────────────────────────────────────
Introduction 1
MKLAPI
───────────────────────────────────────────────────────────────────────────
REALISATION
This package offers a set of drivers with all the functionality of listed
"Purpose" on page 1. Although the OS/2-drivers and DOS-drivers are
completely different implementations, due to the rather extreme differences
in functionality provided by OS/2 and DOS for this type of environment, the
mainline of your railroad control program may be unaware of the underlying
operating system: the application programming interface is identical.
You may read a number of minor differences in "OS/2 and DOS differences" on
page 10.
REGISTRATION
This package is of the 'SHAREWARE' type: You may try it for a reasonably
short time (max 3 months). If you decide to use it for your own railroad
control program, you may show your appreciation and become a 'registered
user'. After registration, I'll send you by mail:
■ A diskette (3-1/2", 720KB), with the following contents:
∙ The most recent version of all the drivers.
∙ Source-files (C-language) of a couple of sample programs provided as
executables in the base package.
■ Complete and up-to-date printed documentation, as well as 2
documentation files on the diskette:
∙ A print-file, formatted for IBM Pro-Printer III.
∙ A file in OS/2 INF format (VIEW-able as online documentation like the
inline OS/2 Command Reference Manual).
After registration you are allowed to distribute the driver as integral
part of your own railroad control application programs. The package (not
the material you get after registration) may be distributed freely with
under the following conditions:
■ it remains a separate and complete package
■ you do not apply changes of any kind
■ you do not make profit with it
The registration fee is 45 Dutch Guilders or equivalent of 25 US-Dollars.
Bare money is accepted as well, but foreign money only in the form of
US-Dollar banknotes.
Please send your comments and registration fee to:
R. Hamerling
Vianen-ZH,
The Netherlands
Postbank acct#: 2087285
PC-Square: FIDOnet 2:512/4.1098
Mention the purpose of your payment ("MKLAPI"), and the destination
address! MKLAPI-source is not included.
───────────────────────────────────────────────────────────────────────────
Introduction 2
MKLAPI
───────────────────────────────────────────────────────────────────────────
FUNCTIONAL DESCRIPTION
This chapter describes a possible use of this package.
OVERVIEW
The Märklin-Interface-driver package is a set of functions to enable direct
communications support in a program written in C-language or BASIC for the
MicroSoft QuickBASIC compiler 4.5((2)) for the family of IBM Personal
System/2 and compatibles.
Please report problems with the driver as soon as you can. and accompany
your report with as much details as might be relevant.
TERMINOLOGY
In this document I use a number of terms which should probably be clarified
first.
Interface The Märklin-Interface. (Märklin partnumber 6050)
Sensor The Märklin S88 encoder. (Märklin partnumber 6088). Sometimes
also called sensor-box or encoder.
Switch The railroad facility, Märklin K83 decoder (Märklin partnumber
6083) is used to control these switch points.
FUNCTIONAL REQUIREMENTS
The Märklin-Interface-driver must provide the following functionality:
■ Possibility to send commands to the Märklin-Interface in any sequence
and mix.
■ Builtin buffered communication with the Märklin-Interface.
■ Automatic flow control between PC and Märklin-Interface.
■ Time-base (clock) for for time-dependent control, independent of
hardware (processor) speed.
■ Automatic readout of sensor-boxes (Märklin S88 encoder): the mainline
must be able to obtain sensor positions instantaneously (without
waittime).
────────────────────
(2) Please note that this driver is delivered in the form of
.OBJ-files, and therefore can be used only with compiled programs
(other .OBJ-files). QBASIC that comes with DOS 5.0 is not capable
of producing an .OBJ file, you'll need the MicroSoft QuickBASIC
compiler 4.5 to use this driver with BASIC programs.
───────────────────────────────────────────────────────────────────────────
Functional description 3
MKLAPI
───────────────────────────────────────────────────────────────────────────
■ Priority mechanism: mainline activities must be handled with higher
priority than 'background' service processes.
■ Ability for emergency stops, regardless of the state of the program or
the model railroad.
PROVIDED FACILITIES
To fulfil the functional requirements, a 'driver' has been built. It
contains a number of service-routines (and for DOS also hardware interrupt
routines), and provides the following facilities:
■ Functions to send train and switch commands to the interface.
Two macro's for output of resp. 1 or 2 consecutive characters (the so
called 1-byte or 2-byte commands). With the 2-byte form the subroutines
ensure that the 2 characters are sent as 2 consecutive characters (not
interrupted by a 'background' task).
■ Functions to read sensors (S88-boxes).
This can either be done by immediate reading the status of the last
polling operation (if polling started). "Reading Märklin S88 encoders"
on page 33 contains details about this mechanism.
If the mainline is sending a command to the Märklin-Interface, polling
is automatically suspended (the command is treated with higher
priority).
■ A 'shadow' of the system timer, but expressed in milliseconds since
program start. This timer has with the OS/2-driver of MKLAPI a
precision of 31.25 msecs, using standard OS/2 facilities (the timer
tick). With the DOS-driver of MKLAPI the posibilities of the hardware
PC timer are explored, giving a precision of 1 millisecond.
■ A trace facility is built in for easy program debugging. All output to
the interface can [optionally] be traced (OS/2 only) and formatted
later.
DELIVERABLES
The shareware components of the Märklin-Interface-driver package are:
| ■ This documentation file: MKLAPI.DOC.
| ■ Header file for C-language: MKLAPI.H with function prototypes, data- and
| macro- definitions.
| ■ Include file for QuickBASIC: MKLAPI.INC with function prototypes.
| ■ 2 OS/2-object decks, MKLAPI2.OBJ (16-bits OS/2 version) and MKLAPI3.OBJ
| (32-bits OS/2 version), with a buffered multitasking communication
| interface, polling, timer-support and trace facility.
| ■ 2 DOS-object decks for C-language programs, SMKLAPI.OBJ and LMKLAPI.OBJ,
───────────────────────────────────────────────────────────────────────────
Functional description 4
MKLAPI
───────────────────────────────────────────────────────────────────────────
| with the same functionality as the OS/2 drivers, (but without a trace
| facility). SMKLAPI is the object deck to be linked with your SMALL
| memory model program, LMKLAPI.OBJ is for LARGE memory model C-language
| programs. LMKLAPI.OBJ is also used for QuickBASIC programs.
■ TRAIN.EXE and TRAIN2.EXE, which are ready to run sample programs for a
DOS and OS/2 environment respectively. See "Sample programs" on page 8
for some characteristics of these programs.
■ MKLTRFMT.EXE, utility to interpret (format) the recorded trace file.
The registration package consists of:
■ Sources (in C-language) of a sample train control program that makes use
of the Märklin driver, usable for OS/2 and DOS ('fullscreen'
application)
■ All include and header files
■ All MAKE and DEF files, used for compilation with MicroSoft C-compiler
6.00a or equivalent, IBM C SET/2 compiler for 32-bits programs and
MicroSoft QuickBASIC compiler 4.5 for QuickBASIC programs.
PREREQUISITES
The package has been built with the following assumptions:
■ Your PC-hardware is 100% compatible with the productline of IBM Personal
Computers (PC, PC/XT, PC/AT, and all current models of the Personal
System/2 family), in particular the asynchronous communication adapters,
their port addresses, etc. and the hardware timer.
■ The operating system is either OS/2 1.2 or higher, or PC-DOS 2.1 or
MS-DOS 2.1 or higher. The package has been tested only with IBM PC/DOS
version 4.0 and 5.0, and with OS/2 version 1.3 and 2.0 (in OS/2
session).
■ Your (16-bits) C-programs (OS/2 and DOS) will be compiled with MicroSoft
C-compiler 6.00a. For 32-bits C-programs IBM C SET/2 compiler is
assumed. There may be some specific requirements on system hardware and
software for these. Maybe Borland Turbo C compiler will work as well,
but this has not been tested.
■ Your BASIC programs will be compiled with the MicroSoft QuickBASIC
compiler 4.5.
RESTRICTIONS AND LIMITATIONS
The following restrictions apply:
■ One single port can be used between open and close of the COM-port to
the Märklin-Interface, all other functions apply to the port chosen at
open-time.
■ The transmit buffer of the DOS-driver is 2048 bytes long, for OS/2 it
───────────────────────────────────────────────────────────────────────────
Functional description 5
MKLAPI
───────────────────────────────────────────────────────────────────────────
depends on COM[xx].SYS, or substitute.
■ Received data is transferred immediately to the sensor-array (64 bytes).
■ When the mainline is sending data to the Märklin-Interface and a
buffer-full situation arises, the data will be discarded. However it is
very unlikely that this will happen in real life.
■ If you read a sensor-box outside the polling-range, the response is
undefined.
TESTS
The drivers have been tested by the author with combinations of the
following hardware and software:
■ model railroad equipment:
∙ Märklin Combined Control
∙ 3 Märklin Digital locs
∙ 3 Märklin K83 decoders, each connected to 4 switch points
∙ 1 Märklin S88 encoder, with railroad-section sensoring
■ computer hardware:
∙ IBM PC/AT-3 (80286/8) with IBM serial-parallel adapter
∙ IBM PS/2 model 80 (80386/16) with standard serial port
∙ IBM PS/2 notebook N51SLC (80386SLC/16) with standard serial port and
second serial port
∙ IBM compatible 80486/33 with multi-I/O card
Note: The DOS-drivers are written in 8086/8 Assembler and should also
work on XT-type systems.
■ Operation Systems:
| ∙ IBM OS/2 2.0: 32-bits mode with MKLAPI3.OBJ, 16-bits mode with
| MKLAPI2.OBJ, DOS-session with LMKLAPI.OBJ
| ∙ IBM OS/2 1.3: MKLAPI2.OBJ
| ∙ IBM PC/DOS 5.0: LMKLAPI.OBJ with QuickBASIC and C-language
Note: Not all combinations of hardware and software have been tested, but
it is not likely that any viable combination will not work.
───────────────────────────────────────────────────────────────────────────
Functional description 6
MKLAPI
───────────────────────────────────────────────────────────────────────────
C-LANGUAGE FRAMEWORK
A typical model railroad control program with this driver may look like:
#include "mklapi.h"
mklopen(1,2400); /* open COM1: */
mklpoll(5); /* 5 S88 boxes in yard */
while (key != ESC) { /* end program from keyboard */
if (kbhit()) { /* keyboard input */
if (key = getch()) { /* normal key (incl alt-numpad) */
switch(key) {
case '?': - - - - - /* your key, your function */
break;
case ESC: break; /* nothing now, exit program */
default: fprintf(stdout,"%c",BEL);
break; /* unsupported normal key */
}
}
else { /* 'special' key */
switch(key = getch()) { /* extended character */
case PgDn: - - - - - /* your 'extended' key function */
break;
default: fprintf(stdout,"%c",BEL);
break; /* unsupported 'extended' key */
}
}
}
for (i=0; i<MAXTRAIN; i++) { /* scan train matrix */
- - - - - /* train control function */
}
for (i=1; i<5, ++i) { /* scan S88 boxes */
mklgetsn(i); /* read sensor bits */
- - - - - - /* process changes */
}
if (!(mkltime()%5000)) { /* every 5 seconds */
- - - - - /* anything else */
}
mklsleep(25); /* give up remainder of timeslice */
}
mklflush(); /* wait until output sent */
mklclose(); /* terminate */
Note: Above code is just a framework to show the general setup of a model
railroad control program using the Märklin-Interface.
───────────────────────────────────────────────────────────────────────────
Functional description 7
MKLAPI
───────────────────────────────────────────────────────────────────────────
QUICKBASIC FRAMEWORK
An equivalent framework in QuickBASIC might look like:
' $INCLUDE: 'MRKAPI.INC'
rc = mklopen(1,2400);
mklpoll(5);
key$ = INKEY$
while key$ <> ESC$
select case key$
case '?'
- - - - -
case ESC
- - - - -
case else
print "error key"
end select
for i=0 to MAXTRAIN
- - - - -
next i
for i=1 to 5
mklgetsn(i)
- - - - - -
next i
if MOD(mkltime,5000) < 50 then
- - - - -
end if
mklsleep(25)
key$ = INKEY$
wend
mklflush;
mklclose;
Note: This code may not be true and workable QuickBASIC!
The file MKLAPI.INC contains the DECLARE lines for all functions contained
in LMKLAPI.OBJ. It should be included in a QuickBASIC program to obtain
the correct calling conventions and activates syntax checking by the
MicroSoft QuickBASIC compiler 4.5. Subsequently the file LMKLAPI.OBJ
should be linked with your QuickBASIC program to include the MKLAPI
functions and subroutines.
SAMPLE PROGRAMS
After registration you will receive the sources a sample (C-language)
program:
■ Control of 8 trains and several other possibilities, with the following
details:
∙ Speed is controlled from the computer keyboard with arrow (cursor)
keys: right-key is faster, left-key is slower, up-key is maximum for
this train, down is maximum backward for this train.
───────────────────────────────────────────────────────────────────────────
Functional description 8
MKLAPI
───────────────────────────────────────────────────────────────────────────
∙ The train for which the command is meant is selected with a
number-key (program provides control for trains 1 through 8). The
corresponding loc-address and other train properties are in a matrix
(with individual entries for each train), such as minimum and maximum
speed in Märklin Central Control values. The train addresses that
are programmed are 10 for train 1, 20 for train 2, etc until 80 for
train 8.
∙ The speed-control is indirect: you tell the system the program
loc-speed, the program does mass-simulation ('slow' increase and
decrease of speed). The parameters for enertia simulation are part
of the train definitions.
∙ For each train its address, desired and actual train speed are
displayed (in color). Direction changes are buffered and automatic.
∙ The display also indicates direction and whether the extra function
is 'on' or 'off'.
■ Control of 4 Märklin K83 decoder for 16 railroad switch points. For
each switch the position ('normal' or 'bound' in color) and its address
is displayed. The keys are A-P for adresses 253-256, and 1-12
respectively.
■ Polling of Märklin S88 encoder each with 16 sensors (or isolated
railroad sections). The position is displayed real time, nothing but
displaying is done with the information. 2 Märklin S88 encoder-boxes
are being polled.
■ Sensor 16 of Märklin S88 encoder-box 1 is designated for speed
measurement. The display shows the time (in milliseconds) between 2
successive 'OFF-ON' transitions. If there is 1 train running and moving
along the same road, this facility can be used for calibrating speed
calculations for each speed-command-value.
■ Other keys:
Insert Set Function 'on'
Delete Set Function 'off'
End Stop polling
Home Restart polling
F3 Stop the program (has to be entered twice consecutively)
Esc Emergency Stop (issues the Märklin Central Control STOP
command)
Enter Resume (issues the Märklin Central Control GO command)
The program may be started with 2 numeric parameters:
1. the first parameter indicates the COM-port to be used (1 for COM1, 2 for
COM2, etc.), The default is COM1.
2. The second parameter indicates the number of Märklin S88 encoder-boxes
to include in the polling mechanism. The default is 2.
───────────────────────────────────────────────────────────────────────────
Functional description 9
MKLAPI
───────────────────────────────────────────────────────────────────────────
OS/2 AND DOS DIFFERENCES
The OS/2-drivers differ from the DOS drivers:
■ The OS/2-drivers are written in C-language, the DOS drivers in
Assembler.
■ The OS/2-driver makes use of the services provided by the standard OS/2
communications driver COM02.SYS (for PS/2) or COM01.SYS for others under
OS/2 version 1.3, and COM.SYS for OS/2 version 2.0. The DOS driver
interfaces directly with the PC hardware.
■ The OS/2-driver makes use of the standard OS/2 facilities for
multithreading (task signalling is done with semaphores). The DOS
driver performs a form of multi-tasking, driven by interrupts (the
COM-port hardware and the standard DOS timer tick).
■ The DOS-drivers explore the possibilities of the hardware timer of the
PC to obtain a accurate time values when needed. With the DOS
timer-tick of 55 msec the average deviation would be about 28 msec.
OS/2 does not allow access to the hardware by 'normal' applications,
therefore the OS/2-drivers use standard OS/2 function calls. Since the
OS/2 timer tick is 31.25 msec, the average deviation will be about 16
msecs.
The sample program under DOS chokes the processor (takes all the cycles
that are available). This is OK in a typical single-task environment, but
not very suitable for a multitasking system. Under OS/2 a very simple
solution for this problem is to insert for example a DosSleep(30L) at the
end of the infinite (keyboard-) loop. There may be better solutions.
───────────────────────────────────────────────────────────────────────────
Functional description 10
MKLAPI
───────────────────────────────────────────────────────────────────────────
SPECIFICATIONS
This chapter describes the use of the provided facilities.
AVAILABLE FUNCTIONS
The following user callable functions are provided:
mklopen Start communication with the Märklin-Interface and the
background tasks.
mklclose Stop background tasks and shutdown the communication with
the Märklin-Interface.
mklputc Transmit 1 or 2 character-commands to the
Märklin-Interface.
mklflush Wait until all data transmitted.
mklpurge Discard remaining data in output buffer.
mklpoll Start or stop polling of Märklin S88 encoder boxes.
mklgetsn Obtain the status of 1 Märklin S88 encoder (when polling
active).
mklstop Set Märklin-Interface in 'stop'-state and stop polling
mklgo Set Märklin-Interface in 'go'-state and (optionally) resume
polling.
mklmsecs Give accurate time in milliseconds since program start
(only in DOS-drivers).
mkltime Give time of last timer tick in milliseconds since program
start.
| mklstats Provide statistics (activity counters).
| mklsleep Pause for a certain time (and give up the remainder of a
| time slice when running in a multitasking environment).
| mklsound Sound generator like BASIC sound or OS/2 DosBeep()
mkltrace Start or stop recording data that is being sent to
Märklin-Interface (only in OS/2-drivers).
The next sections contain the specifications of available functions of the
Märklin-driver, in alphabetical sequence.
Note: The descriptions for C-language and QuickBASIC are given both, but in
the text mainly the C-language notations are used.
MKLCLOSE
Name mklclose - close communications with the Märklin-Interface.
C-language
#include "mklapi.h"
void mklclose(void);
QuickBASIC
' $INCLUDE: 'MKLAPI.INC'
DECLARE SUB MKLCLOSE CDECL ()
───────────────────────────────────────────────────────────────────────────
Specifications 11
MKLAPI
───────────────────────────────────────────────────────────────────────────
Description The close-routine disables the communications task of the
driver. It should be called before termination your
program. Transmits and receives that were in progress will
be terinated, data might be lost.
Return value Nothing.
Related functions "mklopen" on page 15
Warning: mklclose() is not a trivial function! It must be used when
mklopen() has been called succesfully (under DOS). Otherwise your system
may enter a hang-up situation when for no matter what reason your
communications port gives an interrupt. So terminate your program always
'neatly' (so intercept Ctrl-Break in your program to prevent uncontrolled
program termination)!
MKLFLUSH
Name mklflush - flush all buffered output.
C-language
#include "mklapi.h"
int mklflush(void);
QuickBASIC
' $INCLUDE: 'MKLAPI.INC'
DECLARE FUNCTION FLUSH% CDECL ()
Description Wait until all output is sent to the Märklin-Interface. In
other words: wait for empty transmit buffer before
| returning to caller.
| When buffered data is apparently not transmitted anymore,
| the remaining bytes in the transmit buffer will be purged
| and the purge statistics are updated accordingly.
| Return value Depending on success:
| ■ 0 when no more bytes to transmit (buffer empty)
| ■ >0 number of bytes not transmitted (purged) buffer.
■ -1 (DOS) last byte in hardware buffer was not
transmitted
Related functions "mklpurge" on page 16
───────────────────────────────────────────────────────────────────────────
Specifications 12
MKLAPI
───────────────────────────────────────────────────────────────────────────
MKLGETSN
Name mklgetsn - get bit-pattern of a single Märklin S88 encoder.
C-language
#include "mklapi.h"
unsigned short int mklgetsn(short int sensor);
QuickBASIC
' $INCLUDE: 'MKLAPI.INC'
DECLARE FUNCTION MKLGETSN% CDECL (BYVAL SENSOR%)
Description Get a single sensor-box word (16 bits) from the sensor
array.
This function does not generate any action to the
Märklin-Interface and returns the bitsetting immediately.
Polling will have to be started first, with mklpoll(),
before the reading of sensors will give meaningful results.
Reading outside the range 1..31, or higher than the value
as specified with the latest mklpoll(maxsensor) or
| mklgo(maxsensor), will give unpredictable results.
| The Märklin-Interface is always read with 'reset'. The
| resulting 1-bits ('on'-switches) are cumulated until a
| mklgetsn() is called for a specific S88. The caller
| obtains the cumulative bit-setting, but the sensor word is
| refreshed immediately with the results of the last read
| command. Depending on the type of switche used on the
| model railroad, and the frequency in which mklgetsn() is
| issued by the mainline, it may be necessary to issue
| mklgetsn() twice. See for a further explanation: "Reading
| Märklin S88 encoders" on page 33.
Return value A 16-bit word containing the current switch positions.
MKLGO
Name mklgo - send the 'go' command.
C-language
#include "mklapi.h"
int mklgo(short int maxsensor);
QuickBASIC
' $INCLUDE: 'MKLAPI.INC'
DECLARE FUNCTION MKLGO% CDECL (BYVAL MAXSENSOR%)
Description Send the 'go'-command (ASCII 96) to the Märklin-Interface
───────────────────────────────────────────────────────────────────────────
Specifications 13
MKLAPI
───────────────────────────────────────────────────────────────────────────
immediately.
The value of MAXSENSOR has the same meaning and effect as
in mklpoll (see "mklpoll" on page 16). Polling will be
resumed if a non-zero parameter is specified.
OS/2: The go-command is sent via a DevIOCtl operation (send
immediate), and will be followed by a simulated XON. If
there was buffered output (before the stop-state or after
entering stop-state under OS/2 2.0), it will be transmitted
| now.
| OS/2: If the 'go'-command could not be sent, for example if
| the Interface is not ready to accept data, a permanent low
| beep will be heard until the 'go'-button on Märklin Central
| Control is pressed. If an other error occured, mklgo will
| return an error code.
DOS: The go-command is send just as regular data. The
returncode is always zero.
Return value Nothing.
Related functions "mklstop" on page 21, "mklpoll" on page 16
MKLMSECS
Name mklmsecs - obtain time since program start in milliseconds.
C-language
#include "mklapi.h"
unsigned long int void mklmsecs(void);
QuickBASIC
' $INCLUDE: 'MKLAPI.INC'
DECLARE FUNCTION MKLMSECS& CDECL ()
Description (DOS only!) Returns the exact time in milliseconds after
program start without waiting for the next timer tick.
This might be useful for more accurate timing for special
purposes. Of course it takes some time to execute the
necessary instructions to read the timer and format the
information. On faster systems mklmsecs() gives the time a
little more precise than on slower systems, but even on
relatively slow systems it is much more precise than
probably needed for the purpose of mode railroad control!
If this very high precision is not needed, then use the
function mkltime().
(OS/2) This function is 100% equivalent to mkltime().
───────────────────────────────────────────────────────────────────────────
Specifications 14
MKLAPI
───────────────────────────────────────────────────────────────────────────
Return value Time in milliseconds after program start.
Related functions "mkltime" on page 22
MKLOPEN
Name mklopen - open communications line
C-language
#include "mklapi.h"
| int mklopen(short int port, short int speed);
QuickBASIC
' $INCLUDE: 'MKLAPI.INC'
| DECLARE FUNCTION MKLOPEN CDECL (BYVAL PORT%, BYVAL SPEED%)
Description Open and initialise communications port driver, high
resolution timer (DOS only), and set all statistics
counters to zero. The port-parameter may have a value of 1
| to 4, indicating COM1: to COM4:. With DOS the port
| addresses are obtained from BIOS, with OS/2 the COM[xx].SYS
| device driver has them. The interrupt levels are IRQ4 for
| COM1 and COM3, IRQ4 for COM2 and COM4. As you see COM3 may
| conflict with COM1 (and COM2 with COM4). You cannot use
| conflicting interrupt levels at the same time in most
| computers.
Any port will always be initialised with 8-bit, no-parity,
2 stop-bits. The speed parameter should specify 2400,
since it is the only speed supported by the
Märklin-Interface. Maybe later other values?
The counterpart of mklopen() is mklclose(), which should be
called before finishing your (DOS-) program.
| Return value Depending on success:
| ■ 0 - port opened succesfully
| ■ 32 - port probably occupied by another device
| ■ 110 - port not available
| ■ other - see OS/2 or DOS documentation
| With OS/2 the port is opened by a separate thread. When
| the port could not be opened, the whole process will be
| terminated.
Related functions "mklclose" on page 11, "mklstats" on page 19
───────────────────────────────────────────────────────────────────────────
Specifications 15
MKLAPI
───────────────────────────────────────────────────────────────────────────
MKLPOLL
Name mklpoll - start periodic reading of Märklin S88 encoder.
C-language
#include "mklapi.h"
void mklpoll(unsigned int maxsensor);
QuickBASIC
' $INCLUDE: 'MKLAPI.INC'
DECLARE SUB MKLPOLL CDECL (BYVAL MAXSENSOR%)
Description Märklin S88 encoderboxes 1..MAXSENSOR will be read by a
'background' process.
When starting the polling process a 'read with reset' is
issued. The responses of the read-operation are stored in
sensor-arrays. Each word of the array can be read
individually at any time with mklgetsn(). See for details
"Reading Märklin S88 encoders" on page 33.
Return value Nothing
Related functions "mklgo" on page 13 and "mklgetsn" on page 13
MKLPURGE
Name mklpurge - purge output buffer
C-language
#include "mklapi.h"
void mklpurge(void);
QuickBASIC
' $INCLUDE: 'MKLAPI.INC'
DECLARE SUB MKLPURGE CDECL ()
Description Discard current contents of output buffer. If the output
buffer does contain any characters, these are not sent tot
the Interface. After purging the current contents, control
is immediately returned. See also "mklflush" on page 12.
Note: This function is currently available in the driver
for DOS.
Return value Nothing.
Related functions "mklflush" on page 12
───────────────────────────────────────────────────────────────────────────
Specifications 16
MKLAPI
───────────────────────────────────────────────────────────────────────────
MKLPUTC
Name mklputc - send 1 or 2 characters to the interface
C-language
#include "mklapi.h"
int mklputc(unsigned int word);
QuickBASIC
' $INCLUDE: 'MKLAPI.INC'
DECLARE FUNCTION MKLPUTC% CDECL (BYVAL WORD%)
Description Send 1 or 2 characters to the Märklin-Interface. The
'word' is interpreted as two contiguous characters. The
low order byte of the word is sent first, followed by the
high-order byte. If the high is not sent when zero. The
exception to this rule is: if the first byte is a
switch-command (ASCII 33 or 34), then the second byte will
be sent, even when zero.
This function returns immediately, and does not wait for
the bytes to be actually transmitted to the interface. The
communications task will take care to send the buffered
character(s) to the Märklin-Interface.
Coding example to signal speed 8 to loc 27:
rc = mklputc( 27*256 + 8)
For C-language programs it is highly recommended to use the
provided macro's for sending 1 or 2 character commands (see
"Macro Specifications" on page 23).
Warning: When there is no room in the output buffer, then
both characters will be discarded.
Return value 0 character(s) are accepted by the driver.
-1 characters NOT accepted: output discarded.
Note: If you use mklputc() while the driver is in 'stop-state' (see
"mklstop" on page 21):
■ the OS/2-drivers issue a short high-pitch beep. With OS/2 2.0 the data
might be buffered and transmitted after mklgo(). This depends on the
used device driver for the COM-port. COM[xx].SYS does not buffer, but
SIO.SYS does (until its 4KB buffer is full).
■ the DOS-drivers do not generate a warning and will discard the data
until the stop-state is left via a call to mklgo().
───────────────────────────────────────────────────────────────────────────
Specifications 17
MKLAPI
───────────────────────────────────────────────────────────────────────────
MKLSLEEP
| Name mklsleep - pause some time and yield processor
| C-language
| #include "mklapi.h"
| void mklsleep(short int pause);
| QuickBASIC
| ' $INCLUDE: 'MKLAPI.INC'
| DECLARE SUB MKLSLEEP CDECL (BYVAL PAUSE%)
| Description This function provides two facilities:
| ■ It does not return to the caller before the indicated
| pause-interval (im milliseconds) has expired.
| ■ In a multitasking environment (OS/2, DesqView, Windows)
| it releases the processor for this task.
| In the OS/2-driver this function is equivalent to
| DosSleep(). In the DOS-driver it is implemented as a loop
| with an imbedded test for multitasking, in the OS/2-driver
| as DosSleep().
| The pause should be specified in milliseconds, and thus
| cannot exceed about 32 seconds! The specified
| pause-interval is rounded to the next timer tick, but may
| be even larger when the multitasker decides not to give
| control yet to this task after expiration of the interval!
When running a DOS-program in a multitasking environment
(OS/2, Desqview, Windows, etc.), it is desirable to give
control back to the multitasker, when the program does not
need the processor for some time. This part of mklsleep()
is experimental, it may not work with all multitaskers.
The use of mklsleep is not absolutely needed with
pre-emptive multitaskers (like OS/2), but is strongly
recommended. In all cases it reduces CPU utilisation and
leaves processor time for other tasks.
Return value Nothing.
MKLSOUND
Name mklsound - give a 'beep'
C-language
#include "mklapi.h"
void mklsound(short int freq, short int time)
QuickBASIC
───────────────────────────────────────────────────────────────────────────
Specifications 18
MKLAPI
───────────────────────────────────────────────────────────────────────────
' $INCLUDE: 'MKLAPI.INC'
DECLARE SUB MKLSOUND CDECL (BYVAL FREQ%, BYVAL TIME%)
Description Produces a beep-tone with frequency 'freq' expressed in
Hertz, during a period 'time' expressed in milliseconds.
The tone is played in background, all processing continues
without delays or slowdown of the system.
DOS: A beep can be stopped prematurely by calling
mklsound() with a zero frequency, or by mklclose(). A beep
can be changed by mklsound() with a different frequency.
| This will stop any previous beep.
| OS/2: mklsound is implemented as DosBeep and thus behaves
| exactly like it. It is included in the OS/2 driver only
| for source compatibility between OS/2 and DOS programs
| using MKLAPI.
Return value Nothing.
MKLSTATS
Name mklstats - obtain content of statistics counter.
C-language
#include "mklapi.h"
long int mklstats(int counter);
QuickBASIC
' $INCLUDE: 'MKLAPI.INC'
DECLARE FUNCTION MKLSTATS& CDECL (BYVAL COUNTER%)
Description Obtain value of an internal counter in MKLAPI for
statistical purposes. All counters will be reset to zero
with mklopen(), and can also be reset by a user program
through specification of 0 (zero) as parameter.
To read a counter specify a number in the range: 1 to 6.
The counters (by number) have the following contents:
1 Number of accepted commands, including polling-commands
(commands to read S88's). Since the we use a buffering
mechanism, not all of these commands may have been
transmitted actually!
2 Number of internally generated commands to read S88's
('polls').
3 Number of commands that have been discarded. Reasons
may be:
■ system is in 'stop-state'
■ transmit buffer is full
4 Number of bytes that were transmitted. With the
DOS-driver these bytes are actually transmitted to the
───────────────────────────────────────────────────────────────────────────
Specifications 19
MKLAPI
───────────────────────────────────────────────────────────────────────────
COM-port, with OS/2 they were accepted by the device
driver of the COM-port.
5 Number of received bytes (most likely as result
commands to read S88's).
6 Number of bytes that were purged (discarded after first
being accepted, but before actually being transmitted
to the Märklin-Interface). Reasons may be:
■ there were commands buffered while mklstop() was
called
■ mklflush() could not complete (timeout)
■ commands were in the transmit buffer during a call
to mklpurge()
Discarded commands are not counted as 'purged', since
they were not accepted and never put into the transmit
system!
Note: Purging is not supported in the OS/2-drivers, so
this counter should remain zero with OS/2 programs.
Counters in the range 1 to 6 can be considered as permanent
feature of MKLAPI. Counters in the range 7 to 15 are
mainly for debugging purposes. The description below is
for information purposes only, do not use them in your
program, as they may be incorrect, their meaning be changed
in a next version of MKLAPI, or may not be active at all in
the distributed drivers (for performance reasons).
7 DOS: Number of calls to mklputc while the driver's
transmit buffer was empty.
8 DOS: Number of calls to mklputc while the CTS signal is
'high'.
9 DOS: Number of calls to mklputc while the
hardware communications buffer was empty.
10 DOS: Number of calls to mklputc whereby the first or
only byte had to be put in the driver's communications
buffer.
11 Number of calls to mklputc with a request for 2 bytes
(second character always buffered).
12 DOS: Total number of interrupts processed by the
interrupthandler for the asynchronous communications
port.
13 DOS: Number of THRE interrupts.
14 DOS: Number of MSR interrupts (number of CTS signal
changes).
15 DOS: Situations with a pending interrupt after a
previous interrupt was processed.
Specification of a counter number outside the indicated
range will give unpredictable results.
Return value Contents of the specified counter (zero after reset).
Related functions "mklopen" on page 15
───────────────────────────────────────────────────────────────────────────
Specifications 20
MKLAPI
───────────────────────────────────────────────────────────────────────────
MKLSTOP
Name mklstop - send the 'stop' command.
C-language
#include "mklapi.h"
int mklstop(void);
QuickBASIC
' $INCLUDE: 'MKLAPI.INC'
DECLARE FUNCTION MKLSTOP% CDECL ()
Description Send the 'stop'-command (ASCII 97) to the Märklin-Interface
immediately. If polling was active at the time, it will be
| stopped.
| ■ OS/2: A simulated XOFF command is used to indicate the
| COM-driver to hold yet buffered data. The stop-command
| is then sent via a 'send-immediate' operation, ahead of
| data that might be in the transmit buffer. The transmit
| buffer is NOT purged, held data is preserved and sent
| after a 'go'-command.
| You may hear a low beep while the mklstop operation is
| waiting to get access to the Märklin-Interface. If an
| other error occured, mklstop will return an error code.
| ■ DOS: The transmit buffer is purged and the stop-command
| is then sent as regular data. New output is not
| accepted anymore (it will be discarded).
Warning: The 'stop' command could be sent by the mainline
directly, but then would bypass the administrative
functions of the driver. Any train or switchpoint control
command received by the Märklin-Interface will cause a
permanent drop of the CTS signal, making the control over
the railroad from the computer permanently
unavailable. The only possibility to resume control then
is by manually hitting the 'go' key on the Märklin Central
Control.
Note: The timer does not stop with a mklstop(). This may
cause strange effects from time-dependent calculations in
your mainline!
The 'stop' command might interfere with a 2-byte command of
which the first byte was already transmitted, but the
second byte not! In that case the 'stop' would not be
recognised by the Märklin-Interface. Two consecutive
'stop'-commands will prevent the acceptation by the
Märklin-Interface of any further commands from the
computer. To make sure that the 'stop' command will be
processed by the Märklin-Interface, with with the least
───────────────────────────────────────────────────────────────────────────
Specifications 21
MKLAPI
───────────────────────────────────────────────────────────────────────────
inconvenience, MKLAPI precedes the 'stop'-command with a
'go'-command:
■ If there was no command in transmission, then it won't
harm.
■ If a 'broken' 2-byte command was in progress, then the
'go'-byte will be interpreted by the Märklin-Interface
as the second byte. This will probably have a different
effect than was foreseen, but since a 'stop' will
follow, this will be of minor importance.
A secundary effect of this setup is that it allows the
mainline to call mklstop() more than once. The
intermediate 'go' ensures that the Märklin-Interface
doesn't block permanently.
Return value Error code
Related functions "mklgo" on page 13
MKLTIME
Name mkltime - obtain time since program start in milliseconds.
C-language
#include "mklapi.h"
unsigned long int mkltime(void);
QuickBASIC
' $INCLUDE: 'MKLAPI.INC'
DECLARE FUNCTION MKLTIME& CDECL ()
Description Returns the time in milliseconds after program start since
it was updated with the last timer 'tick' (OS/2: 31.25
msecs, DOS: 55 msecs).
This is a little less accurate than mklmsecs, but consumes
also less processor cycles.
Return value Time in milliseconds after program start.
Related functions "mklmsecs" on page 14
MKLTRACE
Name mkltrace - start or stop trace
C-language
#include "mklapi.h"
───────────────────────────────────────────────────────────────────────────
Specifications 22
MKLAPI
───────────────────────────────────────────────────────────────────────────
void mkltrace(short int signal);
QuickBASIC trace facility not provided in DOS drivers
Description Start or stop tracing of all data that is being sent to the
Märklin-Interface and record the information, including a
timestamp into the file MKLAPI.TRC.
When signal is NOT zero, then tracing will be started, or
restarted (old trace data will be discarded in that case).
When signal is zero the trace is stopped and the trace file
closed.
It is my intention to replace this 'on/off' switch with a
trace level facility (selection of events or data to be
traced).
Note: Since a buffered communications interface is used,
the recording of trace data takes place at the moment the
data is sent to the buffer. So the timestamp does not
reflect the exact transmission time. Especially at moments
when Märklin-Interface does not accept data (for example
when it is transmitting Märklin S88 encoder-data), there
may be a significant time difference!
The utility MKLTRFMT.EXE can be used to produce a formatted
trace report. All commands are printed hexadecimal and
interpreted.
See for details about the trace facility and a sample
output: "Appendix B. Trace facility" on page 40.
Return value Nothing.
Note: Tracing is not provided by the DOS-drivers, but a dummy function is
provided for combined OS/2 and OS/2 programs.
MACRO SPECIFICATIONS
A number of C-language only macro's is provided to make specification of
some function-calls a little more simple, and to take care of possibly
needed data conversion.
MKLPUT1C
Name mklput1c - send a single character to the interface.
Usage #include "mklapi.h"
void mklput1c(char);
Prototype in mklapi.h
───────────────────────────────────────────────────────────────────────────
Specifications 23
MKLAPI
───────────────────────────────────────────────────────────────────────────
Description Macro to send a single character in the output buffer. The
macro will expand into a mklputc().
Return value See "mklputc" on page 17.
MKLPUT2C
Name mklput2c - send two characters to the interface.
Usage #include "mklapi.h"
void mklput2c(char1,char2);
Prototype in mklapi.h
Description Macro to send two consecutive character in the output
buffer. The characters will guaranteed be sent in the
given order, without the risk of intervening characters by
the polling mechanism. The macro will expand into a
mklputc().
Return value See "mklputc" on page 17.
USE OF TIMER
At program start with mklopen(), the system time is taken as base for the
functions mkltime and mklmsecs. These functions return a value in
milliseconds after mklopen().
The OS/2-driver uses standard OS/2 facilities, which will allow a precision
of about 16 msecs (the time is updated in OS/2 control blocks every 31.25
msecs).
The DOS-driver uses the system hardware to obtain the system time. This
allows a precision of 1 msec (with the function mklmsecs()). The function
mkltime() gives a precision of about 28 msecs, and takes less machine
instructions, which might be sufficient for most purposes.
The use of this timer facility provided by the MKLAPI-drivers has the
following advantages:
■ It is independent of system (processor) speed and other tasks running in
your system. Many sample programs use some kind of processing loop to
obtain a 'wait'-period, which might be dependent on processor speed and
'choke' the processor, during which time no other useful work is
possible, or at least it is pretty complicated.
■ It is available with very little processor cycles, so it is not needed
to call a 'universal' compiler-provided timer routine, which are
generally much more cycle consuming.
───────────────────────────────────────────────────────────────────────────
Specifications 24
MKLAPI
───────────────────────────────────────────────────────────────────────────
The timer can be used for example for:
■ The application of an event-queue (for timed operations).
■ 'Wait'-intervals during without programming a loop.
■ Simulation of train mass (inertia) through gradually increasing or
decreasing loc-speed.
If you register this package, you'll receive a sample program which makes
use of this feature.
It is recommended to use mklsleep() in cyclic operations when running in a
multitasking environment sucha as Windows, DesqView or in a DOS-session
under OS/2.
QUICKBASIC FUNCTION SPECIFICATIONS
The functionality of the Märklin-driver for QuickBASIC is the same as for
the drivers for C-language. However the following should be noted:
■ BASIC does not allow the underscore-sign ("_") in names, as is very
common in C-language. Therefore the FUNCTIONS and DATA fields in the
Märklin-driver for QuickBASIC have been adapted a little to BASIC
conventions since in 0.9 of these drivers. All other differences are
'under the cover' (but see next item).
■ C-language uses by default a different way of parameter passing than
BASIC, PASCAL and some other languages. But MicroSoft QuickBASIC
compiler 4.5 allows the C-language convention to be used, and the
Märklin-driver for QuickBASIC expects this convention to be used. This
is reflected in the function specifications in MKLAPI.INC. If you use
the MKLAPI.INC file (strongly recommended!), then you won't have to
worry about these conventions.
ERRORS AND SIGNALS
The driver is designed not to disturb your screen with error-messages.
| Therefore audiable signals are used to indicate unexpected problems.
| The OS/2 and DOS-drivers produce the same warning-signals:
| very high pitch, short 3000 Hz, 20 msec: Märklin-Interface The driver is
| in stop-state, but some routine tries to send commands, which
| are discarded.
| medium high pitch, long 2000 Hz, 300 msec: Märklin-Interface seems to be
| long-term blocked. The transmit task could not deliver its
| data. Most likely the transmit buffer is full. Check the
| 'stop'-light on the Märklin Central Control if a stop-condition
| is the cause (manually set, or electrical problem).
| high pitch, short 1000 Hz, 20 msec: A command-transmission did not finish
| within the normal time. Too many commands may be queued, maybe
───────────────────────────────────────────────────────────────────────────
Specifications 25
MKLAPI
───────────────────────────────────────────────────────────────────────────
| because of a program loop.
| medium pitch, short 440 Hz, 100 msec: Flushing of the buffer could not take
| place in the expected time. Either transmission of buffered
| data doesn't take place, or the buffer is being filled during
| flushing faster than can be transmitted.
| low pitch, short 200 Hz, 100 msec: a communications error occurred (OS/2).
| Debugging information might be sent to STDERR (which you might
| have redirected to a log-file to prevent disturbance of your
| screen).
───────────────────────────────────────────────────────────────────────────
Specifications 26
MKLAPI
───────────────────────────────────────────────────────────────────────────
INSTALLATION
APPLICATION DEVELOPMENT CONSIDERATIONS
This MKLAPI is a program development tool with a C-language or QuickBASIC
compiler. You need MKLAPI.H (MKLAPI.INC for BASIC) at compile-time and one
of the .OBJ files at LINK-time. It is an addition to the compiler and
possibly other toolkits you may have for other purposes.
C-COMPILER CONSIDERATIONS
The following compiler properties apply.
■ The file MKLAPI.H must be #included in the program that references the
driver routines (you can use the same header-file for OS/2 and DOS).
■ Memory model: OS/2: LARGE; DOS: SMALL or LARGE (your choice)
■ Calling conventions: C
■ OS/2: The '/MT' parameter should be specified with MicroSoft C-compiler
6.00a With IBM C SET/2 compiler '/Gm' should be specified among other
parameters.
■ Generate underbars: On (Turbo-C option).
Other compiler options are (probably) not of influence on the use of the
Märklin-driver.
MICROSOFT QUICKBASIC COMPILER 4.5 CONSIDERATIONS
The QuickBASIC compiler is needed to create an object deck of your BASIC
program. This OBJect file is combined with LMKLAPI.OBJ file as provided by
this MKLAPI package to build an EXE-file with the LINK utility.
■ Calling conventions: C (DECLARE SUB|FUNCTION xxx CDECL ... etc)
BUILDING AN EXE-FILE
One of the OBJect files should be included in the link-step with your own
OBJect file(s). I prefer to Compile and LINK with the help of the (N)MAKE
utility.
───────────────────────────────────────────────────────────────────────────
Installation 27
MKLAPI
───────────────────────────────────────────────────────────────────────────
C-LANGUAGE AND DOS
For the DOS sample application ("TRAIN") I use the following MAKE-file:
┌─────────────────────────────────────────────────────────────────────────┐
│ │
│ # │
│ # MAKE TRAIN: Marklin Digital Train Control program (DOS version) │
│ # - both SMARKLIN.OBJ and LMARKLIN.OBJ generated │
│ # - LARGE memory model version used for TRAIN.EXE │
│ # - With the compiler variable __DOS__ specified, certain │
│ # #include-file selections are made in train2.c. When │
│ # __DOS__ not specified the OS/2-inlcudes are selected. │
│ # │
│ │
│ MDL=L │
│ CL=-c -Zl -Zp -G0 -W3 -A$(MDL) -D__DOS__ -Fotrain.obj -Ot │
│ LK=/NOD /PACKC:65500 /ST:4000 │
│ │
│ train.exe: train.obj smklapi.obj lmklapi.obj │
│ LINK train+$(MDL)mklapi, train $(LK), nul, $(MDL)LIBCER; │
│ │
│ train.obj: train2.c train.h train.mak attrib.h attrib2.h common.h\ │
│ matrix.h mklapi.h │
│ CL $(CL) train2.c │
│ │
│ smklapi.obj: mklapi.asm mklapi.h train.mak │
│ MASM -Dsmall mklapi.asm,smklapi; │
│ │
│ lmklapi.obj: mklapi.asm mklapi.h train.mak │
│ MASM -Dlarge mklapi.asm,lmklapi; │
│ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Note: It contains switches to control the use of large or small memory
models.
C-LANGUAGE AND BASIC
For a simple test-program in QuickBASIC I use the following batch-file:
┌─────────────────────────────────────────────────────────────────────────┐
│ │
│ @echo off │
│ rem │
│ rem Build Marklin Digital Test program for DOS QuickBASIC │
│ rem Note: LMKLAPI.OBJ fetched from \C2\MARKLIN subdirectory │
│ rem │
│ BC test /S; │
│ if errorlevel 0 LINK test+\c2\marklin\lmklapi; │
│ │
└─────────────────────────────────────────────────────────────────────────┘
───────────────────────────────────────────────────────────────────────────
Installation 28
MKLAPI
───────────────────────────────────────────────────────────────────────────
Note: With MicroSoft QuickBASIC compiler 4.5 the LMKLAPI.OBJ need to be
included in the link. models.
C-LANGUAGE AND OS2 1.3
For the 16-bits OS/2-sample application ("TRAIN2") I use the following
MAKE-file for MicroSoft C-compiler 6.00a and IBM OS/2 Program Development
Toolkit 1.2/1.3:
┌─────────────────────────────────────────────────────────────────────────┐
│ │
│ # │
│ # MAKE TREIN: Marklin Digital Train Control │
│ # │
│ # To be used with MicroSoft C-compiler 6.00a │
│ # │
│ # With IBM C/2 1.1 compiler specify '__IBMC2__' compiler option │
│ # │
│ # 'OS2' compiler variable needed for OS/2 object of TRAIN2! │
│ # │
│ │
│ CL=-c -Zp -Zl -W3 -MT │
│ LK=/A:16 /PACKC:65000 /NOI /NOD │
│ L1=LLIBCMT OS2 │
│ │
│ train2.exe: train2.obj mklapi2.obj train2.def │
│ LINK train2+mklapi2, $@ $(LK), NUL, $(L1), train2.def │
│ │
│ train2.obj: train2.c train2.h attrib2.h mklapi.h common.h matrix.h │
│ CL $(CL) train2.c │
│ │
│ mklapi2.obj: mklapi2.c │
│ CL $(CL) mklapi2.c │
│ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
The contents of the corresponding LINK .DEF-file are:
┌─────────────────────────────────────────────────────────────────────────┐
│ │
│ ; │
│ ;******* Marklin Train Control Program Definition File (.DEF) ******** │
│ ; For: 1) 16-bit version for OS/2 1.3 and MS C-compiler │
│ ; 2) 32-bit version for OS/2 2.0 and IBM C Set/2 compiler │
│ │
│ NAME TRAIN2 WINDOWCOMPAT │
│ │
│ DESCRIPTION 'Marklin Train Control. Copyright (1991,93) Rob Hamerling' │
│ PROTMODE │
│ HEAPSIZE 4096 │
│ STACKSIZE 8192 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
───────────────────────────────────────────────────────────────────────────
Installation 29
MKLAPI
───────────────────────────────────────────────────────────────────────────
C-LANGUAGE AND OS2 2.0+
For the 32-bits OS/2-sample application ("TRAIN3"), the following MAKE-file
is appropriate for IBM C SET/2 compiler and IBM OS/2 Program Development
Toolkit 2.0:
┌─────────────────────────────────────────────────────────────────────────┐
│ │
│ # │
│ # MAKE TREIN: Marklin Digital Train Control program │
│ # │
│ │
│ CL=/c /G3 /Gd+ /Gm+ /Re /Se /Sm /Ss │
│ LK=/NOI /PACKC:65500 /ALIGN:4 /BASE:0x10000 /EXEPACK │
│ │
│ train3.exe: train3.obj mklapi3.obj │
│ link386 $**, $@ $(LK), NUL, , train2.def │
│ │
│ train3.obj: train2.c │
│ icc $(CL) /Fotrain3.obj train2.c │
│ │
│ mklapi3.obj: mklapi2.c mklapi.h │
│ icc $(CL) /Fomklapi3.obj mklapi2.c │
│ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Note: The same .DEF-file is used as for the 16-bit version.
STORAGE AND PERFORMANCE
There is yet not much to say about storage and performance of the driver.
It is highly optimised code, and probably only a minor part of the 'real'
railroad control program.
MEMORY UTILISATION
It is difficult to say how many storage is occupied by the OS/2-version of
the Märklin-driver.
The DOS-version requires about 4K bytes of storage.
PROCESSOR UTILISATION
You might be curious about the cycles that will be consumed by the polling
task. I've done some measurements under OS/2 version 1.3 with the sample
program TRAIN2. On an 8 Mhz AT (80286) the polling takes between 10% and
12% of the processor time (difference in processor utilisation between
polling ON and OFF). This number is practically independent of the number
of Märklin S88 encoder's that are specified for polling, but the polling
frequency is also lower!
───────────────────────────────────────────────────────────────────────────
Installation 30
MKLAPI
───────────────────────────────────────────────────────────────────────────
COMMENTS, REMARKS, BUG-REPORTS
If there are bugs, requirements or questions about this Märklin-driver, the
documentation or the sample program (that you get when you register),
please send me a message through the FIDO network. You can find my name
and node-(point)-number in the introduction of this document.
Enjoy and good luck with your program development! May this driver lead to
a very attractive and succesful model railroad control program!
Do not 'forget' to register!
───────────────────────────────────────────────────────────────────────────
Installation 31
MKLAPI
───────────────────────────────────────────────────────────────────────────
APPENDIX A. MKLAPI INTERNALS
This appendix describes a number of design arguments for this driver and
explains decisions where a choice had to be made.
MULTITASKING
There are many situations in real-time programming, where you want the
system to do something for you, while in the meantime you would like to do
something else in the mainline (before the first piece of program
completes).
An example of this is reading sensor boxes. While you have to wait for the
response of the Märklin S88 encoder, you might want to update your screen,
read data from disk, or process keyboard input. In many sample programs
that I have seen, the wait is frequently done in the form of a short loop
(a for- or while-statement). This means that the processor is working, in
fact consuming cycles, while you cannot do anything (unless you make a more
'complicated' loop). And in many cases you have to experiment with this
loop to get the needed wait-interval (not too long and not too short).
Running the same program on a machine with a different processor-speed,
requires a change in the loop.
A solution for this is to have multiple programs to run simultaneously.
Executing multiple programs (tasks) in parallel is called multi-tasking.
Since we are generally dealing with a single micro processor, the tasks are
simultaneaously present in memory, but only 1 of them is actually
processing. There must be some mechanism to switch the processor between
the tasks.
Some operating environments have standard facilities for this (OS/2,
Windows), but DOS doesn't. Under DOS you have to do it yourself. By
intercepting hardware interupts, or the timer-tick interrupt it is possible
to implement a kind of task-switching.
The polling mechanism in the Märklin-driver is a form of multi-tasking.
For OS/2 it uses the standard OS/2 facilities (called multi-threading), for
DOS it uses the system timer to execute periodical actions independently
from the main-program, and also the hardware interrupts of the asynchronous
communications port to perform some communications work. So in fact there
are two 'extra' tasks in the polling mechanism:
■ Periodically send read-commands to the Märklin-Interface.
■ Receive the responses and put them in the appropriate place in the
sensor-array.
Although you don't have to bother about the polling mechanism, it does have
some influence on the design of your railroad control program. These
practical aspects are explained below.
───────────────────────────────────────────────────────────────────────────
Appendix A. MKLAPI Internals 32
MKLAPI
───────────────────────────────────────────────────────────────────────────
READING MäRKLIN S88 ENCODERS
The driver generates read-sensor commands in the following way:
1. After polling is activated periodically a sensor-read command is
transmitted to read multiple Märklin S88 encoders.
2. The receive-part of the communications task is signalled that a response
from the Märklin-Interface should be expected. The receive continues as
long as not all expected input is received, or an unexpected long time
had to be waited.
3. After processing the response, the system waits some time before issuing
a new read command (typically 100 msec).
4. Even if for some reason the previous poll did not finish within
reasonable time (typically 500 msec), a new read-command is issued.
5. If the transmit routine is in use by the mainline program (such as
sending train-commands), polling is suspended for a short while (shorter
than the normal polling interval).
The Märklin-Interface documentation indicates that the average time to read
the last poll-response is between 45 and 300 milliseconds, depending on how
many Märklin S88 encoder's are being read. From 'life'-tests I have
concluded:
■ The total polling cycle (the time between two consecutive read commands)
is so short that the delay between the change of a switch and making the
change represented in the sensor-array is short enough for most
practical situation.
■ The poll wait interval is long enough to allow sending of many commands
from the mainline between read commands. To make this sure there is a
built-in priority mechanism in the polling routine: it waits with
generating a poll when another program uses mklputc() routine!
■ The frequency of the polls is low enough to ensure that not all CPU
cycles are spent on polling, in stead of 'real' work.
Polling is programmed as follows:
1. After calling mklpoll() of mklgo() with a non-zero parametervalue a
'192'-byte is transmitted, meaning that the Interface will RESET the
bits with next read-sensor commands.
2. Periodically a '128 + MAXSENSOR' byte, meaning that the Interface will
report a group of sensors, up till the limit that was specified with the
latest mklpoll() or mklgo().
| The received data is collected in 2 sensor-arrays:
| 1. Collection of 'raw' data from the Märklin-Interface. Array-1 always
| represents the current switch positions of all polled S88's, apart from
| a slight delay between consecutive reads.
───────────────────────────────────────────────────────────────────────────
Appendix A. MKLAPI Internals 33
MKLAPI
───────────────────────────────────────────────────────────────────────────
| ╔═══════════════════╗
| ║ ║
| ║ Marklin Interface ║
| ║ ║
| ╚═════════════════╝
| ║ ║
| ║ ║
| ╔══════════════════════║══║═════════════════════════════════════╗
| ║ READ S88 1...6 ═══╝ ║ Computer ║
| ║ (by polling task) ║ ║
| ║ ║ ║
| ║ ║ ║
| ║ ╔═════╦═════╦══╩══╦═════╦═════╗ ║
| ║ 'move' ║ ║ ║ ║ ║ ║ ║
| ║ ║ ║ ║ ║ ║ ║ ║
| ║ ╔════╦════╦════╦════╦════╦════╦══ ═ ║
| ║ ║ 1 ║ 2 ║ 3 ║ 4 ║ 5 ║ 6 ║ array-1 ║
| ║ ╚══╦══╩══╦══╩══╦╦═╩══╦══╩══╦══╩══╦══╩══ ═ ║
| ║ ║ ║
| ║ 'or' ║ ║ ║║(2) ║ ║ ║ ║
| ║ ║ ║
| ║ ╔════╦════╦═══╦════╦════╦════╦══ ═ ║
| ║ ║ 1 ║ 2 ║ 3 ║ 4 ║ 5 ║ 6 ║ array-2 ║
| ║ ╚═════╩═════╩══╦══╩═════╩═════╩═════╩══ ═ ║
| ║ ║ ║
| ║ ║(1) actions by: mklgetsn(3) ║
| ║ ║ 1. return word 3 of array-2 ║
| ║ 2. copy word 3 array-1 to array-2 ║
| ║ ║
| ╚═══════════════════════════════════════════════════════════════╝
| Figure 1. Organisation of reading S88's (polling): In this sample a
| group-read of 6 S88-boxes is used.
| 2. Cumulative 'on'-bits since most recent mklgetsn() for each specific S88
| in Array-2.
| The incoming data of the 'read group' is stored in array-1, and all 1-bits
| are copied immediately to array 2 with an 'or'-operation. So array-2 is a
| cumulation of 'on' switch positions during a certain period.
| When mklgetsn(x) is executed, the contents of word-x in array-2 are
| returned to the caller. At the same time word-x in array-2 is refreshed
| with the then current contents of array-1. So a second mklgetsn()
| immediately after the first gives the actual status ((3)).
| A second call is required if you want to know for sure if the switch is
| currently in the 'off'-position after it has been 'on' since the most
| recent mklgetsn().
────────────────────
(3) Function mklgetsn might be changed later to be able to specify that
you need data from the first or from the second array.
───────────────────────────────────────────────────────────────────────────
Appendix A. MKLAPI Internals 34
MKLAPI
───────────────────────────────────────────────────────────────────────────
| This mechanism is suitable for all types of switches that are applied in
| model-railroads, and ensures that you won't miss any 'switch-on' condition,
| even if it is 'on' during a very short period. This organisation is
| illustrated in Reading Märklin S88 encoders on page 33.
You have to be careful with specifying more Märklin S88 encoder boxes in
mklpoll() or mklgo() than you really have in your model railroad yard.
■ It is not useful, since the Märklin-Interface will return all zeroes for
not-connected Märklin S88 encoder's.
■ During the time the Märklin-Interface sends the responses to the
computer, no commands are accepted by the Interface.
So specifying more Märklin S88 encoders than really active will unnecessary
downgrade the responsiveness of your program. You might decide to stop
| polling during processor-intensive work, or not to use polling at all.
| Note: The following consequences of this mechanism:
| ■ If you use this driver, you should not issue read-commands from the
| mainline. The driver does not intercept read-commands from the
| mainline, but it will intercept all data from the Interface and not
| return it to the mainline! This will disturb the administration of the
| internal sensor numbering, which is depending entirely on the number of
| incoming bytes.
| ■ This driver does not yet support physically reading of individual
| Märklin S88 encoders, and it is not possible to use polling with
| no-reset (command 128 in stead of 192). This may look like a
| limitation, especially with the use of reed-switches or contact-rails.
| But once you are familiar with the convenience of the polling mechanism
| and the functionality of mklgetsn(), this should not be a practical
| limitation.
COMMUNICATIONS INTERFACE SPECIFICATION
The Märklin-Interface contains a device driver level communication facility
with between computer and Märklin-Interface, but with a rather high level
interface for the application programmer. It contains many basic
functions, that otherwise have to be programmed yourself. However, it
enforces a specific organisation of your program and has some limitations.
Some of the internals of the communications task are briefly explained to
show why it works as it works now, and may prevent questions. On the other
hand, it may trigger suggestions for changes! Feel free to go in
discussion with me!
Wiring Only the Read (RD), write (TD) and Clear-to-Send (CTS) lead
are connected. Thus using DTR and RTS from the computer
will have no effect of any kind and obviously DSR and DCD
(sometimes also called CD or RLSD) will not be used by the
Märklin-Interface Nevertheless DTR and RTS are set by the
driver with mklopen(). This allows for the use of a
break-out box and/or another computer in stead of the
───────────────────────────────────────────────────────────────────────────
Appendix A. MKLAPI Internals 35
MKLAPI
───────────────────────────────────────────────────────────────────────────
Märklin-Interface for debugging of your program (since a PC
commmunications program usually needs these leads to be
active). The driver itself works properly without the DSR
and DCD leads.
Speed The Märklin-Interface allows only 2400 bps, and 8-bits
data, NO parity, and 2 stop bits. These are the built-in
defaults of the driver, however a different speed can be
specified at open-time (might be useful for test and
debugging).
FIFO So called FIFO hardware buffering, provided by the newer
UART-chips (such as 16550 AFN) on asynchronous
communication ports is handled as follows by the drivers:
■ The DOS-driver does not actively support FIFO-mode, but
FIFO-support is in plan.
■ The OS/2-MKLAPI uses the facilities of the device driver
COM[xx].SYS for operation of the COM-port. When FIFO is
is active for the COM-port before opening, it is left
active and uses this feature. Use the MODE-command to
control this feature.
FIFO-mode may not provide a considerable improvement:
■ The Märklin-Interface operates strictly half-duplex, it
is either in receive mode, or in transmit mode. During
data transfer (either way) CTS is dropped while
transmitting each command-byte and may remain low for a
'considerable' time while command interpretation is in
progress and S88-positions are being sent back to the
computer. This does not suit very well with the FIFO
for transmitbuffering. It might be useful for receive,
since in many cases at least 2 bytes are received per
S88. being read. The support for this is in
consideration.
■ Since the speed is 2400 bps, most systems can easily
keep up with the non-buffered mode of operation. The
highly effective interrupt handler of the DOS-driver may
make the netto effect of reduced CPU-cycles for
interrupt handling only minimal.
But FIFO-mode may be helpful in a multitasking environment.
Use the MODE command with BUFFER=ON, to activate it, when
desired.
Output flow control The CTS signal is dropped by Märklin-Interface during
data transfer (during receive and transmit: the
Märklin-Interface is strictly half-duplex). The CTS signal
is used for 'hardware output flow control' from the
computer. So the transmit routines will not send data when
CTS is not high, but will automatically resume transmission
when CTS rises and the buffer contains any data to
transmit.
DOS Although not strictly needed, the DOS-version of the
Märklin-driver has the transmit interrupt (THRE) active to
───────────────────────────────────────────────────────────────────────────
Appendix A. MKLAPI Internals 36
MKLAPI
───────────────────────────────────────────────────────────────────────────
be able to run the driver against a full-duplex interface
(with continuous CTS), such as another PC with a diagnostic
communications program. The transmit interrupt uses the
same code as the MSR interrupt.
For initial testing of programs without actually running a
model railroad, you could use a 'wrap-plug' to partially
simulate the Märklin-Interface. The RTS signal (raised by
the driver) is feeded back to CTS, so the driver is always
able transmit.
If also send and receive (generally pins 2 and 3) leads are
wrapped back, then the transmitted data is treated as S88
response. This may cause
Input flow control There is no form of input flow control allowed by the
Märklin-Interface: there is no way to signal the
Märklin-Interface to stop sending. This will not be a
problem for the driver, since there is enough buffering and
CPU-power to process the low volume input in time.
XON/XOFF flow control Not used. This type of flow-control is not supported
by the Märklin-Interface, since the commands for the
Märklin-Interface may contain these characters!
OS/2: The standard COM[xx].SYS of OS/2 allows simulated
XON/XOFF. A DosDevIOCtl-'XOFF' is issued to stop
transmitting buffered data when a 'stop'-command has to be
transmitted. A DosDevIOCtl-'XON' is issued when a
subsequent 'go'-command is issued.
Null stripping The OS/2 COM[xx].SYS allows null stripping. There are at
least 2 reasons for this feature not to be activated:
■ Märklin S88 encoder's may respond with all bits zero
■ Switch 256 is addressed as ASCII 0.
Command parsing The driver does not interpret the data it sends to the
Märklin-Interface. It means that it is completely the
responsibility of the mainline to ensure proper command
sequences.
Note: The driver does not send automatically a
switch-'relax' command (ASCII 32) after a switch command
(ASCII 33 or 34)! You may write a shell for Märklin
command syntax checking.
PROBLEMS WITH OS/2 COM[XX].SYS
The Com-port driver of some versions of OS/2 for non-PS/2 machines
(COM01.SYS) does have some known problems, such as:
■ READ and WRITE timout specifications cannot be changed from the built-in
default of 1 minute.
───────────────────────────────────────────────────────────────────────────
Appendix A. MKLAPI Internals 37
MKLAPI
───────────────────────────────────────────────────────────────────────────
When encountering this kind of problems, I could recommend Gerry Rozema's
replacement driver for AT-type machines (COM16540.SYS, or COM16550.SYS, as
appropriate for your system's COM-port). For OS/2 2.0 there is also a
driver SIO.SYS by Ray Gwinn, that might be useful when having problems with
the standard OS/2 2.0 drivers.
These alternative drivers are available on Bulletin Boards such as
PC-Square in The Netherlands (FIDO node 2:512/4, telephone 31.79.424107).
OS/2 AND DOS DIFFERENCES
Although all versions of this Märklin-driver offer a consistent application
programming interface for communication with the Märklin-Interface, it is
most likely that there will be differences between the programs using
either of them. Some of these differences might be:
■ When running in a multitasking environment, the program should give
other tasks the chance to run (yield the processor).
∙ With OS/2 other tasks will get some control automatically
(pre-emptive multi-tasking), but nevertheless the program should at
least use DosSleep(0) when it does not need the processor for some
time.
∙ DOS: apart from the built-in multitasking of the Märklin-driver which
controls itself, you probably won't run other programs. In that case
you will not have to release the processor.
∙ When running a DOS-program under another multitasker (Windows,
Desqview), periodic calls of mklsleep() are recommended.
■ The OS/2 driver makes use of the standard multitasking (multithreading)
facilities. Therefore any program using this driver should specify /MT
for MicroSoft C-compiler 6.00a. The different include-search might be
indicated with a compiler option (-I for most C-compilers).
The DOS driver should use the normal include directory.
■ The OS/2 driver requires the LARGE memory model compiler options and use
the LLIBCMT library for LINK (automatic with /MT). The DOS-version is
for either the SMALL (/AS) or LARGE memory model (/AL), use the
respectively the SLIBCE or LLIBCE library with LINK.
■ The standard OS/2-driver (COM[xx].SYS) will not accept new output data
in stop-state, but will transmit possibly retained data (from before
mklstop) after a call to 'mklgo'. Some alternative drivers (such as
SIO.COM) do accept new data from mklputc, but keep it internally
buffered. No more data is accepted when the buffer is full. After
mklgo() all buffered data, old and new, will be transmitted.
The DOS-drivers refuse all new output data in stop-state.
■ It is an absolute must, that the Märklin-driver under DOS is terminated
with a call to mklclose() to de-activate the interrupts for com-port and
timer. Therefore it is recommended to use a routine to intercept Ctrl-C
or Ctrl-Break actions from the keyboard.
───────────────────────────────────────────────────────────────────────────
Appendix A. MKLAPI Internals 38
MKLAPI
───────────────────────────────────────────────────────────────────────────
Under OS/2 this attitude is recommended, but not an absolute must.
In both cases it is recommended to direct the Ctrl-C signal to a
controlled finish of your railroad control program: you probably do not
want to terminate your program with uncontrolled running trains!
■ The display of information about the state of your railroad on the
computer screen will probably use different techniques, such as the way
cursor and color will be used:
1. OS/2: Presentation Manager (graphics) or VIO routines.
2. DOS: Windows (graphics)
3. ANSI escape-sequences (compatible between OS/2 and DOS)
The sample program you'll receive after registration is a single source
for environments 1 and 3. My own programs are primarily for OS/2 and I
prefer to use the OS/2 facilities and those of the Program Development
Toolkit as good as possible. For instance I use VIO-routines for color
and cursor manipulation.
To be able to run my sample program under DOS, I included some extra
routines in the header-file. These routines translate color and cursor
manipulations with OS/2 VIO-calls into equivalent ANSI escape sequences.
When ANSI is active under DOS (with DEVICE=[path]\ANSI.SYS in
CONFIG.SYS), the visual effects are the same as with the OS/2 version.
When there is no possibility to use the same code for OS/2 and DOS, you
might consider using a compiler variable (with the -D compiler option) to
distinguish which pieces of codes are OS/2 or DOS specific. See for an
example the MAKE-files in the MKLAPI package.
───────────────────────────────────────────────────────────────────────────
Appendix A. MKLAPI Internals 39
MKLAPI
───────────────────────────────────────────────────────────────────────────
APPENDIX B. TRACE FACILITY
TRACE RECORDS
The trace facility produces the following records (8 bytes each):
long int timestamp; /* value of mkltime */
int fl:1, /* flag: 0=output, 1=input */
nn:7, /* (in start-of-trace record) trace source */
/* MKLAPI: DOS = 1; OS/2 1.x = 2; OS/2 2.x = 3 */
sw:8; /* S88 box number on input */
char c1, /* first character */
c2; /* second character */
The first record after starting a trace contains 0xFF as first and second
character.
SAMPLE
The output of the trace formatting program MKLTRFMT will look like:
time I/O cmd data description
------------ --- --- ---- --------------------------------------
45.050 Start of trace (MKLAPI OS/2 1.x)
+0.045 O 1A 13 Loc 19 speed 10 Funktion=ON
+0.350 O 22 3F switchpoint 63: branch
+0.760 O 20 switchpoint release
+1.850 O C0 read S88's with reset
+4.850 O 82 read S88 1 t/m 2
+4.881 I 1801 S88 1 ON=4,5,16
+4.881 I 090E S88 2 ON=,8,13,14,15
+5.000 O 61 STOP
This is not a complete trace, just some parts to show the essentials.
MKLTRFMT.EXE is a 'family mode' application: it will run under OS/2 and
DOS. No parameters are required, but you may specify the input filename
[including path] if your trace is in another directory or named other than
MKLAPI.TRC, which is the default (output filename of MKLAPI).
MKLTRFMT writes the output to 'stdout', which is normally the computer
display. But the output may be redirected to your printer or to a file.
So you could use for example the command:
MKLTRFMT >TRACE.FMT
so that you could look afterwards with a text editor or file browse utility
| in TRACE.FMT for the formatted trace.
───────────────────────────────────────────────────────────────────────────
Appendix B. Trace facility 40
MKLAPI
───────────────────────────────────────────────────────────────────────────
| APPENDIX C. MäRKLIN-INTERFACE PECULIARITIES
| When writing a model railroad control program (with or without this
| driver), you should be aware of some peculiarities, which are not very well
| (or not at all) documented by Märklin. With experiments during development
| of MKLAPI I have found for example:
| ■ Sending 2 consecutive change-direction commands to the same loc does not
| put the loc back in the original direction. A zero-speed command
| between them is a good circumvention.
| ■ When the Märklin-Interface is in 'stop'-state:
| ∙ Permanent blocking (having to push the 'go'-button on the Märklin
| Central Control) does occur only with commands to train-decoders and
| switch-point or light decoders (K83 or K84).
| ∙ Reading Märklin S88 encoders (polling) may continue. But since the
| changes are not sent from the control-box to the Märklin-Interface,
| it is not very useful.
───────────────────────────────────────────────────────────────────────────
Appendix C. Märklin-Interface peculiarities 41
MKLAPI
───────────────────────────────────────────────────────────────────────────
APPENDIX D. SUMMARY OF CHANGES
0.7 First beta release: June 1992
0.8 released: October 1992
■ The time-base value in mkltime has been changed from 55 msec to 1
msec!(updating of mkltime still on timer-tick basis: once per 55
msecs in DOS, once per 31.25 msecs in OS/2).
■ DOS: High precision timer routine added: mklmsecs(). This gives
the period since line to opening of communication with
Märklin-Interface with 1 msec accuracy.
■ OS/2: Trace facility added (see also "Appendix B. Trace facility"
on page 40), start and stop of trace via procedure call
mkltrace(). Output to and input from the Märklin-Interface is
traced. A trace-file formatting utility (MKLTRFMT.EXE) is added
to package. I have tried to add this trace facility also in the
DOS driver, but I did not cucceed so far. It is rather
complicated to use DOS facilities during interrupt handling
(tracing must be located in the com-port and timer interrupt
routines).
■ A procedure 'mklsleep' added to make your DOS-program 'friendly'
for some popular multitasking environments (such DOS-box of OS/2,
Desqview, Windows).
■ DOS: mklflush times out after 3 seconds when transmit buffer could
not be flushed.
■ Some bugs fixed:
∙ mklflush() of OS/2 version watched the INput in stead of OUTput
queue.
∙ DOS: DTR and RTS now turned off before finishing program.
0.9 released: March 1993
■ A 32-bits driver for OS/2 2.0+ (MKLAPI3.OBJ) has been added, with
same functionality as MKLAPI2, including the new features below!
■ 'MKLAPI' now also useable by programs translated with the
MicroSoft QuickBASIC compiler 4.5. Since QuickBASIC does not
allow underscores in names, all externally used names have been
changed, for example: mklopen() is now called mklopen(). The
C-language calling convention must be specified in the source (see
MKLAPI.INC), and the file LMKLAPI.OBJ should be used with LINK.
All function specifications have been changed, and additions made
for program development with MicroSoft QuickBASIC compiler 4.5.
■ mkltime() is not anymore an external variable, but a function
returning the value of the time, expressed in milliseconds, but
with the precision of the timer tick.
■ mklmsecs() now also a function returning the time, but in exact
milliseconds (DOS only).
■ With the OS/2 drivers, the transmissions in STOP-state (after
mklstop) may now be buffered in stead of discarded (until buffer
full, then discarded). This depends on the COM.SYS device
drivers, or replacements thereof.
■ After the first mklstop subsequent calls of mklstop are ignored
and nothing sent to the Märklin-Interface until mklgo has been
called.
■ mklstop() and mklgo() now give a returncode (0 = OK, otherwise a
transmission problem exists).
───────────────────────────────────────────────────────────────────────────
Appendix D. Summary of changes 42
MKLAPI
───────────────────────────────────────────────────────────────────────────
■ Simple Switchpoint test program (incl c-source) added to MKLAPI
package.
■ Added counters for and a function mklstats() for statistical
purposes and debugging.
■ Polling optimised: a single 'reset after read S88' (192) is issued
after mklpoll() and mklgo(), subsequently only 'read group of n
S88s' (128+n) commands are sent periodically (previously both
commands were sent after each interval).
1.0 released: May 1993
■ Names and references to 'MARKLIN' renamed to MKLAPI, where the
driver is meant (and not Märklin-components). Include-files and
sources that include header files should be changed.
■ DOS-drivers now take RS232 port addresses from the BIOS data-area,
and performs a simple check if the port is not already in use.
■ Sound support added to DOS-drivers, and the function made callable
by mainline. Warning signals of OS/2- and DOS-drivers
'harmonised'.
■ Polling and storage of S88 bit-settings changed to get better
operation for all types of switches.
■ mklstop() and mklgo() made more reliable.
■ mklsleep() accepts now specification of an interval (pause) time
■ mklmsecs(), mklsound() and mklsleep() functions now present in
both OS/2 and DOS versions for more compatibility between OS/2 and
DOS versions of programs that make use of the MKLAPI-driver.
───────────────────────────────────────────────────────────────────────────
Appendix D. Summary of changes 43